package cn.turboinfo.dongying.api.gateway.admin.controller.login;

import cn.turboinfo.dongying.api.gateway.admin.fo.login.LoginTokenFO;
import cn.turboinfo.dongying.api.gateway.admin.constant.AdminConstants;
import cn.turboinfo.dongying.api.gateway.admin.fo.login.LoginFO;
import cn.turboinfo.dongying.api.gateway.admin.fo.login.LoginTokenFO;
import cn.turboinfo.dongying.api.gateway.admin.framework.http.ResponseBodyWrapper;
import cn.turboinfo.dongying.api.provider.admin.component.config.AdminKitConfig;
import cn.turboinfo.dongying.api.provider.admin.component.log.AdminLoginLogHelper;
import cn.turboinfo.dongying.api.provider.admin.component.security.SecurityEncoder;
import cn.turboinfo.dongying.api.provider.admin.component.session.AdminSessionHelper;
import cn.turboinfo.dongying.api.gateway.admin.constant.AdminConstants;
import cn.turboinfo.dongying.api.gateway.admin.fo.login.LoginFO;
import cn.turboinfo.dongying.api.gateway.admin.fo.login.LoginTokenFO;
import cn.turboinfo.dongying.api.gateway.admin.framework.http.ResponseBodyWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sunshow.toolkit.core.base.enums.YesNoStatus;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.SessionException;
import org.apache.shiro.subject.Subject;
import org.springframework.session.Session;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Map;
import java.util.UUID;

@Slf4j
@RequiredArgsConstructor
@Controller
@ResponseBodyWrapper
@RequestMapping(value = "/admin")
public class AdminUserLoginController {

    private final AdminSessionHelper sessionHelper;

    private final AdminLoginLogHelper loginLogHelper;

    private final AdminKitConfig adminKitConfig;

    private final SecurityEncoder securityEncoder;

    @PostMapping(value = "/login")
    public LoginTokenFO login(HttpServletRequest request, @RequestBody @Valid LoginFO user) {
        if (adminKitConfig.isLoginCaptchaEnable()) {
            String captchaInSession = (String) request.getSession().getAttribute(AdminConstants.AttrDefaultCaptcha);
            if (StringUtils.isEmpty(captchaInSession) || !captchaInSession.equals(user.getCaptcha())) {

                loginLogHelper.save("login", user.getUsername(), null, YesNoStatus.NO, "验证码不正确");
                throw new RuntimeException("验证码不正确");
            }
        }

        Subject subject = SecurityUtils.getSubject();

        String password = securityEncoder.decrypt(user.getPassword());

        UsernamePasswordToken loginToken = new UsernamePasswordToken(user.getUsername(), password, false);
        Long sysUserId = null;
        try {
            subject.login(loginToken);
            sysUserId = (Long) subject.getPrincipal();

            // 如果未允许相同账户多处登录 需要进行会话检查
            if (!adminKitConfig.isLoginConcurrentEnable()) {
                // 如果此账号已在其它地方登录
                Map<String, Session> sessionMap = sessionHelper.findSessionMap(sysUserId);
                if (!sessionMap.isEmpty()) {
                    long current = System.currentTimeMillis();
                    for (Session session : sessionMap.values()) {
                        // 5分钟没活动的会话踢掉
                        if (current - session.getLastAccessedTime().toEpochMilli() > adminKitConfig.getLoginConcurrentTimeout()) {
                            sessionHelper.deleteSessionById(session.getId());
                            /*
                            if (user.isForceLogin()) {
                                adminSessionHelper.deleteSessionById(session.getId());
                            } else {
                                throw new AuthenticationException("当前用户已在其他设备登录，可以选择踢出", new SessionException("当前用户已在其他设备登录"));
                            }
                            */
                        } else {
                            throw new SessionException("当前用户已在其他设备登录，请稍后重试");
                        }
                    }
                }
            }

            loginLogHelper.save("login", user.getUsername(), sysUserId, YesNoStatus.YES, null);
            // 登录成功后设置 session
            sessionHelper.initSession();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            subject.logout();
            if (e instanceof SessionException) {
                loginLogHelper.save("login", user.getUsername(), sysUserId, YesNoStatus.NO, "当前用户已在其他设备登录");
                throw new RuntimeException("当前用户已在其他设备登录");
            } else {
                loginLogHelper.save("login", user.getUsername(), sysUserId, YesNoStatus.NO, "用户名或密码不正确");
                throw new RuntimeException("用户名或密码不正确");
            }
        }

        String adminToken = UUID.randomUUID().toString();
        // String adminToken = "admin-token";
        subject.getSession().setAttribute("ADMIN-TOKEN", adminToken);

        return new LoginTokenFO(adminToken);
    }

    @RequestMapping(value = "/logout")
    @ResponseBodyWrapper
    public void logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
    }

}
